/**
 * 通用uni-app网络请求
 * 基于 Promise 对象实现更简单的 request 使用方式，支持请求和响应拦截
 */
import {
	getHost
} from '@/utils/url.js';
import {
	setAuthorization,
	getAuthorization
} from '@/router/auth.js';
import {
	apiBaseURL
} from '@/config/index.js';
// 刷新token
import {
	authLogin
} from '@/api/public.js';
// 请求错误自定义
let errorCode = {
	403: '当前操作没有权限',
	404: '访问资源不存在',
	default: '系统未知错误,请反馈给管理员',
};
// 请求存储
let axiosPromiseArr = [];
// loading白名单
let loadWhite = [];
/**
 * 判断是否为JSON格式
 * @param {*} str
 * @returns
 */
function isJSON(str) {
	if (typeof str == 'string') {
		try {
			JSON.parse(str);
			return true;
		} catch (e) {
			return false;
		}
	}
}
/**
 * 创建缓存key, 由请求url、类型、参数、发送数据构成的标识符
 * @param {string} url 请求url
 * @param {string} type 请求类型
 * @param {object} data 请求数据
 * @return {string}
 */
function createKey({
	url,
	method,
	data = {}
}) {
	return encodeURIComponent([url, method, isJSON(data) ? data : JSON.stringify(data)].join(','));
}
let isRefreshing = false,
	needRetryRequest = [];
let config = {
		header: {
			'Content-Type': 'application/json;charset=UTF-8'
		},
		data: {},
		method: "GET",
		// 如果设为 json，会尝试对返回的数据做一次 JSON.parse
		dataType: "json",
	},
	// 请求拦截器
	interceptor = {
		/**
		 * 请求前置拦截器（参数处理）
		 */
		request: (config) => {
			// 必须要传入url
			if (!config.url) throw new Error('ajax url is required!');
			if (!getHost(config.url)) config.url = apiBaseURL + config.url;
			// 是否需要设置 token
			const isToken = (config.header || {}).isToken === false,
				token = getAuthorization('accessToken');
			if (!isToken && token) {
				config.header['Authorization'] = 'Bearer ' + token; // 让每个请求携带自定义token
				config.header['gc-authentication'] = token;
			}
			delete config.header.isToken
			// 创建全局loading，排除不需要loading的接口
			if (axiosPromiseArr.length === 0 && !loadWhite.includes(config.url) && !config.url.includes('notReadNum')) uni.showLoading({
				title: '加载中...',
			})
			const key = createKey(config);
			axiosPromiseArr.push(key);
			config.sslVerify = false;
			return config;
		},
		/**
		 * 请求后置拦截器（数据处理）
		 */
		response: (res, resolve, reject, config) => {
			// 请求状态，未设置则默认为200
			let code = res.data.code || 200;
			// 获取错误信息
			const msg = errorCode[code] || res.data.msg || errorCode['default'];
			if ([401, '401'].includes(code)) {
				if (getAuthorization('username') && getAuthorization('password') && !isRefreshing && getAuthorization('accessToken')) {
					isRefreshing = true;
					return authLogin({
						username: getAuthorization('username'),
						password: getAuthorization('password'),
					}).then(res => {
						const {
							data,
						} = res;
						console.log('data', data);
						const accessToken = data.tk
						setAuthorization('accessToken', accessToken);
						// token 刷新后将数组的方法重新执行
						needRetryRequest.forEach((cb) => cb(accessToken))
						needRetryRequest = [] // 重新请求完清空
						config.header['Authorization'] = 'Bearer ' + accessToken; // 让每个请求携带自定义token
						config.header['gc-authentication'] = accessToken;
						uni.request(config)
					}).catch(() => {
						uni.reLaunch({
							url: '/pages/login/login'
						})
						setTimeout(() => {
							uni.showToast({
								title: '登录失败',
								icon: 'error'
							});
							reject(res.data);
						})
					}).finally(() => {
						isRefreshing = false;
					})
				} else if (isRefreshing) {
					// 返回未执行 resolve 的 Promise
					new Promise(resolve => {
						// 用函数形式将 resolve 存入，等待刷新后再执行
						needRetryRequest.push(token => {
							config.header['Authorization'] = 'Bearer ' + token; // 让每个请求携带自定义token
							config.header['gc-authentication'] = token;
							resolve(uni.request(config))
						})
					})
				} else {
					if (!isRefreshing) {
						uni.reLaunch({
							url: '/pages/login/login'
						})
						setTimeout(() => {
							uni.showToast({
								title: '身份证已过期，请重新登录',
								icon: 'error'
							});
							reject(res.data);
						})
					}
				}
			} else if (!(code == 200 || code == 1)) {
				setTimeout(() => {
					uni.showToast({
						title: msg,
						icon: 'error'
					});
				}, 0)
				reject(res.data);
			} else {
				resolve(res.data);
			}
		},
	};
/**
 * 请求方法
 */
const apiFn = function(options = {}) {
	// 基于 Promise 的网络请求
	return new Promise((resolve, reject) => {
		/**
		 * 请求前置拦截器
		 */
		let _config = interceptor.request({
			...config,
			...options
		});
		// 请求成功
		_config.success = res => {
			interceptor.response(res, resolve, reject, _config)
		}
		// 请求失败
		_config.fail = error => {
			let {
				errMsg
			} = error;
			if (errMsg) {
				if (errMsg == 'Network Error') {
					errMsg = '后端接口连接异常';
				} else if (errMsg.includes('timeout')) {
					errMsg = '系统接口请求超时';
				} else if (errMsg.includes('Request failed with status code')) {
					errMsg = '系统接口' + errMsg.substr(errMsg.length - 3) + '异常';
				}
				setTimeout(() => {
					uni.showToast({
						title: errMsg,
						icon: 'error'
					})
				}, 0)
			}
			reject(error);
		}
		// 接口调用结束的回调函数（调用成功、失败都会执行）
		_config.complete = () => {
			setTimeout(() => {
				axiosPromiseArr.pop();
				// 全部请求结束关闭loading
				if (axiosPromiseArr.length === 0) uni.hideLoading();
			}, 500)
		}
		// 发送请求
		return uni.request({
			..._config,
		});
	});
}
export default apiFn